package user

import (
	"cross-shard-channel/common"
	"encoding/json"
	"github.com/eywa-protocol/bls-crypto/bls"
	"io/ioutil"
	"net/http"
)

// 定义回复请求的函数
func InitOpenRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin InitOpenRespond")

	// 定义基本结构
	var requestObject InitOpen
	var responseObject InitOpenResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// 构造通道账户和最终通道UTXO
	myChPri, myChPub := GenerateKeyWithPub(requestObject.ChannelPubA)
	channelFinalPub := requestObject.ChannelPubA.Aggregate(myChPub)

	// 生成回复数据，需要操作UserNode信息
	UN.Lock()
	inputUTXOB := common.UTXO{
		UN.Pub,
		[]byte("0"),
		requestObject.AdvBalance,
	}
	UN.AddNewChannelToNode(requestObject.Cid, requestObject.InputUTXOA.PublicKey,
		r.RemoteAddr, requestObject.AdvBalance, requestObject.InputUTXOA.Balance, requestObject.LifeTime)
	tarChannel := UN.Channels[requestObject.Cid]
	UN.Unlock()

	inputUTXOs := []common.UTXO{requestObject.InputUTXOA, inputUTXOB}
	createUTXO := common.UTXO{
		channelFinalPub,
		nil,
		requestObject.InputUTXOA.Balance + requestObject.AdvBalance,
	}
	outputUTXOs := []common.UTXO{createUTXO}
	createTx := common.GenerateTransactionByUTXO(inputUTXOs, outputUTXOs, 0)
	createUTXO.Tx_id = createTx.TxId[:]

	// 将通道创建信息附加到相应通道实例上
	tarChannel.Lock()
	tarChannel.Type = 1
	tarChannel.MyBalance = requestObject.AdvBalance
	tarChannel.AdvBalance = requestObject.InputUTXOA.Balance
	tarChannel.InputCreateUTXOB = inputUTXOB
	tarChannel.InputCreateUTXOA = requestObject.InputUTXOA
	tarChannel.MyChPri = myChPri
	tarChannel.MyChPub = myChPub
	tarChannel.AdvChPub = requestObject.ChannelPubA
	tarChannel.ChannelPub = channelFinalPub
	tarChannel.CreateUTXO = createUTXO
	tarChannel.TxCreate = *createTx
	tarChannel.Unlock()

	// 构造 response body
	responseObject.Cid = requestObject.Cid
	responseObject.InputUTXOB = inputUTXOB
	responseObject.ChannelPubB = myChPub
	responseObject.ChannelPubFinal = channelFinalPub

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	tarChannel.Show()
	//println("InitOpenRespond success")
	return
}

func OpenNotifyRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin OpenNotifyResponse")

	// 定义基本结构
	var requestObject OpenNotify
	var responseObject OpenNotifyResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// 获取自己的数据
	UN.Lock()
	myPub := UN.Pub
	myPri := UN.Pri
	UN.Unlock()

	// 获取通道实例数据
	ch := UN.GetChannelFromNode(requestObject.Cid)
	ch.Lock()
	advPub := ch.Adv
	ch.Unlock()

	myNotifyPri, myNotifyPub := GenerateKeyWithPub(advPub)
	notifyPubA := advPub.Aggregate(myNotifyPub)

	// 构建给对方的通知交易
	notifyOutputA := common.UTXO{
		notifyPubA,
		nil,
		0,
	} // 这个实际上是给Adv的通知
	notifyInputA := common.UTXO{
		myPub,
		[]byte("0"),
		0,
	}
	TxNotifyA := common.GenerateTransactionByUTXO([]common.UTXO{notifyInputA}, []common.UTXO{notifyOutputA}, 0)
	NotifyASig := TxNotifyA.Sign(myPri)
	TxNotifyA.Sigs = []bls.Signature{NotifyASig}

	// 构造 response body
	responseObject.Cid = responseObject.Cid
	responseObject.TxNotify = *TxNotifyA

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	// 修改状态信息
	ch.Lock()
	ch.MyNotifyPri = myNotifyPri
	ch.MyNotifyPub = myNotifyPub
	ch.NotifyUTXOB = requestObject.TxNotify.Output[0]
	ch.NotifyUTXOA = responseObject.TxNotify.Output[0]
	ch.Unlock()

	//println("OpenNotifyResponse success")
	return
}

func OpenAccountRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin OpenAccountRespond")

	// 定义基本结构
	var requestObject OpenAccount
	var responseObject OpenAccountResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// 获取相关信息
	ch := UN.GetChannelFromNode(requestObject.Cid)
	ch.Lock()
	advChPub := ch.AdvChPub
	ch.Unlock()

	// 新建一个公私钥对，用于构建对方的锁定账户
	lockPriForMe, lockPubForMe := GenerateKeyWithPub(advChPub)
	// 构造回复信息
	responseObject.Cid = requestObject.Cid
	responseObject.LockPub = lockPubForMe

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	// 修改本地记录
	ch.Lock()
	ch.AdvLockPubs = append(ch.AdvLockPubs, requestObject.LockPub)
	ch.MyLockPubs = append(ch.MyLockPubs, lockPubForMe)
	ch.MyLockPris = append(ch.MyLockPris, lockPriForMe)
	ch.Unlock()

	//println("OpenAccountRespond Success")
}

func OpenUnlockRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin OpenUnlockResponse")

	// 定义基本结构
	var requestObject OpenUnlock
	var responseObject OpenUnlockResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// 获取相关信息
	ch := UN.GetChannelFromNode(requestObject.Cid)
	ch.Lock()
	advMainPub := ch.Adv
	myChPub := ch.MyChPub
	myChPri := ch.MyChPri

	myChBalance := ch.MyBalance
	advChBalance := ch.AdvBalance

	createUTXO := ch.CreateUTXO
	notifyUTXOA := ch.NotifyUTXOA
	notifyUTXOB := ch.NotifyUTXOB

	lockTime := ch.LifeTime
	// lock account information
	myLockPri := ch.MyLockPris[0]
	advLockPub := ch.AdvLockPubs[0]
	ch.Unlock()

	// 验证获取到的交易签名是否正确
	mySig := requestObject.TxUnlockB.Sign(myLockPri)
	requestObject.TxUnlockB.Sigs = []bls.Signature{requestObject.Sig.Aggregate(mySig)}
	if !requestObject.TxUnlockB.Verify() {
		println("ERROR: Open Unlock Fail")
	}

	// 新建一个公私钥对，用于构建对方的锁定账户
	lockPubA := myChPub.Aggregate(advLockPub)

	// 构建对方的commit交易
	commitInputs := []common.UTXO{createUTXO, notifyUTXOA, notifyUTXOB}
	commitOutputA := common.UTXO{
		lockPubA,
		nil,
		advChBalance,
	}
	commitOutputB := common.UTXO{
		myChPub,
		nil,
		myChBalance,
	}

	commitOutputs := []common.UTXO{commitOutputA, commitOutputB}
	commitTx := common.GenerateTransactionByUTXO(commitInputs, commitOutputs, 0)
	commitOutputA.Tx_id = commitTx.TxId

	// 构建给对方的解锁交易
	unlockInputs := []common.UTXO{commitOutputA}
	unlockOutputUTXO := common.UTXO{
		advMainPub,
		nil,
		commitOutputA.Balance,
	}
	unlockOutputs := []common.UTXO{unlockOutputUTXO}
	unlockTx := common.GenerateTransactionByUTXO(unlockInputs, unlockOutputs, lockTime)
	unlockSigB := unlockTx.Sign(myChPri)

	// 构造回复信息
	responseObject.Cid = requestObject.Cid
	responseObject.Sig = unlockSigB
	responseObject.TxUnlockA = *unlockTx
	responseObject.TxCommitA = *commitTx

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	// 记录本地数据
	ch.Lock()
	ch.TxUnlocks = []common.Transaction{}
	ch.TxCommits = []common.Transaction{}
	ch.AdvTxCommits = []common.Transaction{}

	ch.TxCommits = append(ch.TxCommits, requestObject.TxCommitB)
	ch.TxUnlocks = append(ch.TxUnlocks, requestObject.TxUnlockB)
	ch.AdvTxCommits = append(ch.AdvTxCommits, *commitTx)
	ch.Unlock()

	//println("OpenUnlockResponse success")
	return
}

func OpenCommitRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin OpenCommitResponse")

	// 定义基本结构
	var requestObject OpenCommit
	var responseObject OpenCommitResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// 获取相关信息
	UN.Lock()
	myMainPub := UN.Pub
	myMainPri := UN.Pri
	UN.Unlock()

	ch := UN.GetChannelFromNode(requestObject.Cid)
	ch.Lock()
	myChPri := ch.MyChPri
	myNotifyPri := ch.MyNotifyPri

	advCommitTx := ch.AdvTxCommits[0]
	myCommitTx := ch.TxCommits[0]
	ch.Unlock()

	// 验证对方发送的内容是否有效
	myMainSig := myCommitTx.Sign(myMainPri)
	myChSig := myCommitTx.Sign(myChPri)
	myNotifySig := myCommitTx.Sign(myNotifyPri)

	sig0 := requestObject.ChSigA.Aggregate(myChSig)       // for channel fund
	sig1 := requestObject.MainSigA.Aggregate(myNotifySig) // for NotifyUTXOA
	sig2 := myMainSig.Aggregate(requestObject.NotifySigA) // for NotifyUTXOB
	myCommitTx.Sigs = []bls.Signature{sig0, sig1, sig2}

	if !myCommitTx.Verify() {
		println("open-commit signature error!")
	}

	// 构造给对方的签名
	advMainSig := advCommitTx.Sign(myMainPri)
	advChSig := advCommitTx.Sign(myChPri)
	advNotifySig := advCommitTx.Sign(myNotifyPri)

	// 生成回复
	responseObject.Cid = requestObject.Cid
	responseObject.MainSigB = advMainSig
	responseObject.ChSigB = advChSig
	responseObject.NotifySigB = advNotifySig

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	// 构建给自己的refund transaction
	refundInputs := []common.UTXO{advCommitTx.Output[1]}
	refundOutputs := []common.UTXO{common.UTXO{
		myMainPub,
		nil,
		advCommitTx.Output[1].Balance,
	}}
	myRefundTx := common.GenerateTransactionByUTXO(refundInputs, refundOutputs, 0)
	sigRefund := myRefundTx.Sign(myChPri)
	myRefundTx.Sigs = []bls.Signature{sigRefund}

	// 记录本地数据
	ch.Lock()
	ch.TxRefunds = []common.Transaction{}

	ch.TxCommits[0].Sigs = []bls.Signature{sig0, sig1, sig2}
	ch.TxRefunds = append(ch.TxRefunds, *myRefundTx)
	ch.Unlock()

	//println("Open Commit Success")
}

func OpenCreateRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin OpenCreateResponse")

	// 定义基本结构
	var requestObject OpenCreate
	var responseObject OpenCreateResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// 获取本地信息
	UN.Lock()
	myMainPri := UN.Pri
	ch := UN.Channels[requestObject.Cid]
	UN.Unlock()

	ch.Lock()
	txCreate := ch.TxCreate
	ch.Unlock()

	sigB := txCreate.Sign(myMainPri)
	txCreate.Sigs = []bls.Signature{requestObject.SigA, sigB}

	if !txCreate.Verify() {
		println("open-commit signature error!")
	}

	responseObject.Cid = requestObject.Cid
	responseObject.SigB = sigB

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	ch.Lock()
	ch.Version = 0
	ch.Unlock()
	//println("OpenCreate Success")
}
